package com.sugar.real.estate.module.business.service.openedcity;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sugar.real.estate.framework.common.util.object.BeanUtils;
import com.sugar.real.estate.module.business.controller.admin.openedcity.vo.OpenedCityListReqVO;
import com.sugar.real.estate.module.business.controller.admin.openedcity.vo.OpenedCitySaveReqVO;
import com.sugar.real.estate.module.business.controller.app.infocls.vo.AppGetCityRespVO;
import com.sugar.real.estate.module.business.controller.app.infocls.vo.AppOpenedCityRespVO;
import com.sugar.real.estate.module.business.dal.dataobject.openedcity.OpenedCityDO;
import com.sugar.real.estate.module.business.dal.mysql.openedcity.OpenedCityMapper;
import com.sugar.real.estate.module.business.util.I18nUtil;
import com.sugar.real.estate.module.business.util.TreeUtil;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.sugar.real.estate.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.real.estate.module.business.enums.ErrorCodeConstants.*;

/**
 * 已开通城市 Service 实现类
 *
 * @author Ysugar
 */
@Service
@Validated
public class OpenedCityServiceImpl implements OpenedCityService {

    @Resource
    private OpenedCityMapper openedCityMapper;

    @Override
    public Long createOpenedCity(OpenedCitySaveReqVO createReqVO) {
        // 校验父级ID的有效性
        validateParentOpenedCity(null, createReqVO.getParentId());
        // 校验城市名称（中文）的唯一性
        validateOpenedCityNameUnique(null, createReqVO.getParentId(), createReqVO.getNameZhCn(), createReqVO.getNameEnUs());

        // 插入
        OpenedCityDO openedCity = BeanUtils.toBean(createReqVO, OpenedCityDO.class);
        openedCityMapper.insert(openedCity);
        // 返回
        return openedCity.getId();
    }

    @Override
    public void updateOpenedCity(OpenedCitySaveReqVO updateReqVO) {
        // 校验存在
        validateOpenedCityExists(updateReqVO.getId());
        // 校验父级ID的有效性
        validateParentOpenedCity(updateReqVO.getId(), updateReqVO.getParentId());
        // 校验城市名称的唯一性
        validateOpenedCityNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getNameZhCn(), updateReqVO.getNameEnUs());

        // 更新
        OpenedCityDO updateObj = BeanUtils.toBean(updateReqVO, OpenedCityDO.class);
        openedCityMapper.updateById(updateObj);
    }

    @Override
    public void deleteOpenedCity(Long id) {
        // 校验存在
        validateOpenedCityExists(id);
        // 校验是否有子已开通城市
        if (openedCityMapper.selectCountByParentId(id) > 0) {
            throw exception(OPENED_CITY_EXITS_CHILDREN);
        }
        // 删除
        openedCityMapper.deleteById(id);
    }

    @Override
    public Long getSameOpenedCity(String name, Long parentId) {
        if (StrUtil.isBlank(name))
            return null;
        if (Objects.isNull(parentId))
            return null;
        OpenedCityDO openedCityDO = openedCityMapper.selectOne(Wrappers.<OpenedCityDO>lambdaQuery()
                .eq(OpenedCityDO::getParentId, parentId)
                .nested(o -> o.eq(OpenedCityDO::getNameZhCn, name).or().eq(OpenedCityDO::getNameEnUs, name))
                .last("LIMIT 1"));

        if (Objects.isNull(openedCityDO)){
            openedCityDO = new OpenedCityDO();
            // 判断首字母若是字母则为国外
            openedCityDO.setType(RandomUtil.BASE_CHAR.contains(String.valueOf(name.toLowerCase().charAt(0))))
                    .setNameZhCn(name)
                    .setNameEnUs(name)
                    .setParentId(parentId);
            openedCityMapper.insert(openedCityDO);
        }

        return openedCityDO.getId();
    }

    private void validateOpenedCityExists(Long id) {
        if (openedCityMapper.selectById(id) == null) {
            throw exception(OPENED_CITY_NOT_EXISTS);
        }
    }

    private void validateParentOpenedCity(Long id, Long parentId) {
        if (parentId == null || OpenedCityDO.PARENT_ID_ROOT.equals(parentId)) {
            return;
        }
        // 1. 不能设置自己为父已开通城市
        if (Objects.equals(id, parentId)) {
            throw exception(OPENED_CITY_PARENT_ERROR);
        }
        // 2. 父已开通城市不存在
        OpenedCityDO parentOpenedCity = openedCityMapper.selectById(parentId);
        if (parentOpenedCity == null) {
            throw exception(OPENED_CITY_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父已开通城市，如果父已开通城市是自己的子已开通城市，则报错，避免形成环路
        if (id == null) { // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            parentId = parentOpenedCity.getParentId();
            if (Objects.equals(id, parentId)) {
                throw exception(OPENED_CITY_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父已开通城市
            if (parentId == null || OpenedCityDO.PARENT_ID_ROOT.equals(parentId)) {
                break;
            }
            parentOpenedCity = openedCityMapper.selectById(parentId);
            if (parentOpenedCity == null) {
                break;
            }
        }
    }

    private void validateOpenedCityNameUnique(Long id, Long parentId, String nameZhCn, String nameEnUs) {
        OpenedCityDO openedCity = openedCityMapper.selectByParentIdAndNameZhCn(parentId, nameZhCn, nameEnUs);
        if (openedCity == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的已开通城市
        if (id == null) {
            throw exception(OPENED_CITY_NAME_ZH_CN_DUPLICATE);
        }
        if (!Objects.equals(openedCity.getId(), id)) {
            throw exception(OPENED_CITY_NAME_ZH_CN_DUPLICATE);
        }
    }

    @Override
    public OpenedCityDO getOpenedCity(Long id) {
        return openedCityMapper.selectById(id);
    }

    @Override
    public List<OpenedCityDO> getOpenedCityList(OpenedCityListReqVO listReqVO) {
        return openedCityMapper.selectList(listReqVO);
    }

    @Override
    public AppGetCityRespVO getTopOpenedCity() {
        List<OpenedCityDO> topCityList = openedCityMapper.selectList(OpenedCityDO::getParentId, 0);
        Map<Boolean, List<AppOpenedCityRespVO>> topCityListGroupByTypeMap = topCityList
                .stream()
                .map(o -> BeanUtils.toBean(o, AppOpenedCityRespVO.class))
                .collect(Collectors.groupingBy(AppOpenedCityRespVO::getType));

        AppGetCityRespVO respVO = new AppGetCityRespVO();
        List<AppOpenedCityRespVO> chinaProvinceList = topCityListGroupByTypeMap.get(false);
       /* List<AppOpenedCityRespVO> chinaList = new ArrayList<>();
        for (AppOpenedCityRespVO chinaProvince : chinaProvinceList) {
            chinaList.addAll(BeanUtils.toBean(openedCityMapper.selectList(OpenedCityDO::getParentId, chinaProvince.getId()), AppOpenedCityRespVO.class
                    , o -> o.setName(I18nUtil.getMessage(o, "getName"))));
        }*/

        List<AppOpenedCityRespVO> abroadProvinceList = topCityListGroupByTypeMap.get(true);
       /* List<AppOpenedCityRespVO> abroadList = new ArrayList<>();
        for (AppOpenedCityRespVO abroadProvince : abroadProvinceList) {
            abroadList.addAll(BeanUtils.toBean(openedCityMapper.selectList(OpenedCityDO::getParentId, abroadProvince.getId()), AppOpenedCityRespVO.class
                    , o -> o.setName(I18nUtil.getMessage(o, "getName"))));
        }*/

        respVO.setChinaList(chinaProvinceList).setAbroadList(abroadProvinceList);
        return respVO;
    }

    @Override
    public List<AppOpenedCityRespVO> getOpenedCityByParentId(Long parentId) {
        List<OpenedCityDO> topCityList = openedCityMapper.selectList(OpenedCityDO::getParentId, parentId);
        return BeanUtils.toBean(topCityList, AppOpenedCityRespVO.class
                , o -> o.setName(I18nUtil.getMessage(o, "getName")));
    }

    @Override
    public AppGetCityRespVO getOpenedCityTreeList() {
        List<OpenedCityDO> allCity = openedCityMapper.selectList();

        Map<Boolean, List<AppOpenedCityRespVO>> topCityListGroupByTypeMap = allCity
                .stream()
                .map(o -> BeanUtils.toBean(o, AppOpenedCityRespVO.class))
                .collect(Collectors.groupingBy(AppOpenedCityRespVO::getType));

        AppGetCityRespVO respVO = new AppGetCityRespVO();
        respVO.setAbroadList(TreeUtil.listConvertTree(topCityListGroupByTypeMap.get(true)))
                .setChinaList(TreeUtil.listConvertTree(topCityListGroupByTypeMap.get(false)));
        return respVO;
    }
}